Up to now, we have seen how named patterns could be used to define flat schemas which are more modular, easier to ready when the number of elements and attributes grows and can be used define recursive content models. In this chapter we will see how they can be used as building blocks to build libraries of content models that can be assembled to create complete schemas. To do so, we will introduce examples which can be seen as basic use cases for these features.

!!! External references

!!With Russian doll schemas

The first use case is when we want to reuse existing schemas as a whole, without modifying their definitions. Imagine, for instance that we have defined two grammars in two schemas to describe our "author" and "character" elements. We have a first Relax NG schema to describe our authors:

 <?xml version="1.0" encoding="UTF-8"?>
 <element name="author" xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <attribute name="id">
     <data type="ID"/>
   </attribute>
   <element name="name">
     <data type="token" datatypeLibrary=""/>
   </element>
   <optional>
     <element name="born">
       <data type="date"/>
     </element>
   </optional>
   <optional>
     <element name="died">
       <data type="date"/>
     </element>
   </optional>
 </element>
(author.rng)

or:

 element author {
   attribute id { xsd:ID },
   element name { token },
   element born { xsd:date }?,
   element died { xsd:date }?
 }
(author.rnc)

And a second one to describe our characters:

 <?xml version="1.0" encoding="UTF-8"?>
 <element name="character" xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <attribute name="id">
     <data type="ID"/>
   </attribute>
   <element name="name">
     <data type="token" datatypeLibrary=""/>
   </element>
   <optional>
     <element name="born">
       <data type="date"/>
     </element>
   </optional>
   <element name="qualification">
     <data type="token" datatypeLibrary=""/>
   </element>
 </element>
(character.rng)

or:

 element character { element library {
   element book {
     attribute id { xsd:ID },
     attribute available { xsd:boolean },
     element isbn { token },
     element title {
       attribute xml:lang { xsd:language },
       token
     },
     external "author.rnc" +,
     external "character.rnc" *
   }+
 }
   attribute id { xsd:ID },
   element name { token },
   element born { xsd:date }?,
   element qualification { token }
 }
(character.rnc)

If we want to use them in a schema describing our library, we will use "externalRef" patterns:

 <?xml version="1.0" encoding="UTF-8"?>
 <element name="library" xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <oneOrMore>
     <element name="book">
       <attribute name="id">
         <data type="ID"/>
       </attribute>
       <attribute name="available">
         <data type="boolean"/>
       </attribute>
       <element name="isbn">
         <data type="token" datatypeLibrary=""/>
       </element>
       <element name="title">
         <attribute name="xml:lang">
           <data type="language"/>
         </attribute>
         <data type="token" datatypeLibrary=""/>
       </element>
       <oneOrMore>
         <externalRef href="author.rng"/>
       </oneOrMore>
       <zeroOrMore>
         <externalRef href="character.rng"/>
       </zeroOrMore>
     </element>
   </oneOrMore>
 </element>

In the compact syntax, "externalRef" patterns are translated into keyword "external":

 element library {
   element book {
     attribute id { xsd:ID },
     attribute available { xsd:boolean },
     element isbn { token },
     element title {
       attribute xml:lang { xsd:language },
       token
     },
     external "author.rnc" +,
     external "character.rnc" *
   }+
 }

These patterns have a semantic of straight inclusion: when a Relax NG processor reads a schema it just replaces "externalRef" by the content of the referred document.

!!With flat schemas 

In this first example, we've been using "externalRef" with "Russian doll" schemas, but this would work fine too with flat schemas. For instance, if we change our schemas to:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   
   <start>
     <ref name="element-author"/>
   </start>
   
   <define name="element-author">
     <element name="author">
       <attribute name="id">
         <data type="ID"/>
       </attribute>
       <ref name="element-name"/>
       <optional>
         <ref name="element-born"/>
       </optional>
       <optional>
         <ref name="element-died"/>
       </optional>
     </element>
   </define>
   
   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   
   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>
   
   <define name="element-died">
     <element name="died">
       <data type="date"/>
     </element>
   </define>
   
 </grammar>

or:

 start = element-author
 element-author =
   element author {
     attribute id { xsd:ID },
     element-name,
     element-born?,
     element-died?
   }
 element-name = element name { token }
 element-born = element born { xsd:date }
 element-died = element died { xsd:date }

 And:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
 
   <start>
     <ref name="element-character"/>
   </start>
   
   <define name="element-character">
     <element name="character">
       <attribute name="id">
         <data type="ID"/>
       </attribute>
       <ref name="element-name"/>
       <optional>
         <ref name="element-born"/>
       </optional>
       <ref name="element-qualification"/>
     </element>
   </define>
   
   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   
   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>
   
   <define name="element-qualification">
     <element name="qualification">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>

 </grammar>

or:

 start = element-character
 element-character =
   element character {
     attribute id { xsd:ID },
     element-name,
     element-born?,
     element-qualification
   }
 element-name = element name { token }
 element-born = element born { xsd:date }
 element-qualification = element qualification { token }

!!Embedded grammars

This seems straightforward and logical, but why does that work? How come that there is no collision between the named patterns "element-name" and  "element-born" defined in both "author.rng" and "character.rng"? How come that "start" patterns defined in "author.rng" and "character.rng" do not apply to the schema for our library?

This is working because we are using a feature called "embedded grammars". As I have already mentioned, the semantic of "externalRef" patterns is a strict inclusion of the referred schema and in our last example, this means that our resulting schema is:

 <?xml version="1.0" encoding="UTF-8"?>
 <element name="library" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <oneOrMore>
     <element name="book">
       <attribute name="id">
         <data type="ID"/>
       </attribute>
       <attribute name="available">
         <data type="boolean"/>
       </attribute>
       <element name="isbn">
         <data type="token" datatypeLibrary=""/>
       </element>
       <element name="title">
         <attribute name="xml:lang">
           <data type="language"/>
         </attribute>
         <data type="token" datatypeLibrary=""/>
       </element>
       <oneOrMore>
         <grammar>
           <start>
             <ref name="element-author"/>
           </start>
           <define name="element-author">
             <element name="author">
               <attribute name="id">
                 <data type="ID"/>
               </attribute>
               <ref name="element-name"/>
               <optional>
                 <ref name="element-born"/>
               </optional>
               <optional>
                 <ref name="element-died"/>
               </optional>
             </element>
           </define>
           <define name="element-name">
             <element name="name">
               <data type="token" datatypeLibrary=""/>
             </element>
           </define>
           <define name="element-born">
             <element name="born">
               <data type="date"/>
             </element>external "character.rnc"
           </define>
           <define name="element-died">
             <element name="died">
               <data type="date"/>
             </element>
           </define>
         </grammar>
       </oneOrMore>
       <zeroOrMore>
         <grammar>
           <start>
             <ref name="element-character"/>
           </start>
           <define name="element-character">
             <element name="character">
               <attribute name="id">
                 <data type="ID"/>
               </attribute>
               <ref name="element-name"/>
               <optional>
                 <ref name="element-born"/>
               </optional>
               <ref name="element-qualification"/>
             </element>
           </define>
           <define name="element-name">
             <element name="name">
               <data type="token" datatypeLibrary=""/>
             </element>
           </define>
           <define name="element-born">
             <element name="born">
               <data type="date"/>
             </element>
           </define>
           <define name="element-qualification">
             <element name="qualification">
               <data type="token" datatypeLibrary=""/>
             </element>
           </define>
         </grammar>
       </zeroOrMore>
     </element>
   </oneOrMore>
 </element>

or:

 element library {
   element book {
     attribute id { xsd:ID },
     attribute available { xsd:boolean },
     element isbn { token },
     element title {
       attribute xml:lang { xsd:language },
       token
     },
     grammar {
       start = element-author
       element-author =
         element author {
           attribute id { xsd:ID },
           element-name,
           element-born?,
           element-died?
         }
       element-name = element name { token }
       element-born = element born { xsd:date }
       element-died = element died { xsd:date }
     }+,
     grammar {
       start = element-character
       element-character =
         element character {
           attribute id { xsd:ID },
           element-name,
           element-born?,
           element-qualification
         }
       element-name = element name { token }
       element-born = element born { xsd:date }
       element-qualification = element qualification { token }
     }*
   }+
 }

Here we are thus embedding grammars within our schema and they behave as patterns. In fact that's even more than that: for Relax NG, grammars are patterns! The semantic of these patterns is twofold:

*As far as validation is concerned, embedded grammars are equivalent to their start patterns: the grammar describing the "character" element for instance will instance nodes corresponding to its start pattern, i.e. instance nodes matching the pattern "element-character" which is what we were expecting.
*Grammars are also setting the scope of their definitions: "start" and named patterns defined in a grammar are visible only in this grammar. Their scope (i.e. the location where they can be referred to) is strictly limited to the grammar in which they are defined.

Applied to our example, the strict scoping of "start" and named patterns means that:

*The "born" pattern of the grammar describing the "character" element cannot be seen from its parent grammar, i.e. the grammar describing the "library" and "book" elements nor from its sibling grammar, i.e. the grammar describing the "author" element. The same applies to "start" patterns.
*Unlike common usage among programming languages, the scope of "start" and named patterns do not include embedded grammars and "start" and named patterns defined in the grammar describing "library" and "book" elements would not be visible in the embedded grammars.

!!Reference to a pattern in the parent grammar

This strict isolation of "start" and named patterns in their grammars is usually what we need in references to external grammars. It means that these external grammars can be written independently without any risk of collision or incompatibility. Or in other words that you can take any Relax NG schema and drop it into a new schema to see it as a single pattern without any risk of collision.

On the other hand, that doesn't let you modify what you are including (we will see how to do so in the next section) nor even to leverage on a set of common named patterns. In our example, since we already had two definitions of "element-name" and "element-born", that was a good thing that they have been isolated in their grammars. Now, if we were designing the same building blocks from scratch, we would probably want to have only one definition of these two elements which are common to the "author" and "character" elements. In fact if we were following the principle "if it's written more than once make it common" we would also want to share the definition of the "id" attribute.

We will see another way to do so, but it is also possible to do so through making an explicit reference to a pattern from the parent grammar, i.e. the grammar embedding the current one. In this case, we need to add the definitions which we want to share in the top level schema even if we do not use all of theme in this schema:

<?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

   <start>
     <element name="library">
       <oneOrMore>
         <element name="book">
           <ref name="attribute-id"/>
           <attribute name="available">
             <data type="boolean"/>
           </attribute>
           <element name="isbn">
             <data type="token" datatypeLibrary=""/>
           </element>
           <element name="title">
             <attribute name="xml:lang">
               <data type="language"/>
             </attribute>
             <data type="token" datatypeLibrary=""/>
           </element>
           <oneOrMore>
             <externalRef href="author.rng"/>
           </oneOrMore>
           <zeroOrMore>
             <externalRef href="character.rng"/>
           </zeroOrMore>
         </element>
       </oneOrMore>
     </element>
   </start>

   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   
   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>
   
   <define name="attribute-id">
     <attribute name="id">
       <data type="ID"/>
     </attribute>
   </define>
   
 </grammar>

or:

 start =
   element library {
     element book {
       attribute-id,
       attribute available { xsd:boolean },
       element isbn { token },
       element title {
         attribute xml:lang { xsd:language },
         token
       },
       external "author.rnc"+,
       external "character.rnc"*
     }+
   }
 element-name = element name { token }
 element-born = element born { xsd:date }
 attribute-id = attribute id { xsd:ID }

Now, to make a reference to the named patterns "element-name", "element-born" and "attribute-id" in the embedded grammars, we will use a pattern called "parentRef":

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <start>
     <ref name="element-author"/>
   </start>
   <define name="element-author">
     <element name="author">
       <attribute name="id">
         <data type="ID"/>
       </attribute>
       <parentRef name="element-name"/>
       <optional>
         <parentRef name="element-born"/>
       </optional>
       <optional>
         <ref name="element-died"/>
       </optional>
     </element>
   </define>
   <define name="element-died">
     <element name="died">
       <data type="date"/>
     </element>
   </define>
 </grammar>
(author.rng)

and:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <start>
     <ref name="element-character"/>
   </start>
   <define name="element-character">
     <element name="character">
       <attribute name="id">
         <data type="ID"/>
       </attribute>
       <parentRef name="element-name"/>
       <optional>
         <parentRef name="element-born"/>
       </optional>
       <ref name="element-qualification"/>
     </element>
   </define>
   <define name="element-qualification">
     <element name="qualification">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
 </grammar>
(character.rng)

The "parentRef" pattern is translated to a "parent" keyword in the compact syntax:

 start = element-author
 element-author =
   element author {
     attribute id { xsd:ID },
     parent element-name,
     parent element-born?,
     element-died?
   }
 element-died = element died { xsd:date }
(author.rnc)

and:

 start = element-character
 element-character =
   element character {
     attribute id { xsd:ID },
     parent element-name,
     parent element-born?,
     element-qualification
   }
 element-qualification = element qualification { token }
(character.rnc)

Here again, we are using these features in the context of multiple schema documents, but the semantic of the "externalRef" pattern is unchanged from the previous section and this schema is equivalent to the same schema with the "externalRef" patterns expended in a single monolithic schema with two embedded grammars:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <start>
     <element name="library">
       <oneOrMore>
         <element name="book">
           <ref name="attribute-id"/>
           <attribute name="available">
             <data type="boolean"/>
           </attribute>
           <element name="isbn">
             <data type="token" datatypeLibrary=""/>
           </element>
           <element name="title">
             <attribute name="xml:lang">
               <data type="language"/>
             </attribute>
             <data type="token" datatypeLibrary=""/>
           </element>
           <oneOrMore>
             <grammar>
               <start>
                 <ref name="element-author"/>
               </start>
               <define name="element-author">
                 <element name="author">
                   <attribute name="id">
                     <data type="ID"/>
                   </attribute>
                   <parentRef name="element-name"/>
                   <optional>
                     <parentRef name="element-born"/>
                   </optional>
                   <optional>
                     <ref name="element-died"/>
                   </optional>
                 </element>
               </define>
               <define name="element-died">
                 <element name="died">
                   <data type="date"/>
                 </element>
               </define>
             </grammar>
           </oneOrMore>
           <zeroOrMore>
             <grammar>
               <start>
                 <ref name="element-character"/>
               </start>
               <define name="element-character">
                 <element name="character">
                   <attribute name="id">
                     <data type="ID"/>
                   </attribute>
                   <parentRef name="element-name"/>
                   <optional>
                     <parentRef name="element-born"/>
                   </optional>
                   <ref name="element-qualification"/>
                 </element>
               </define>
               <define name="element-qualification">
                 <element name="qualification">
                   <data type="token" datatypeLibrary=""/>
                 </element>
               </define>
             </grammar>
           </zeroOrMore>
         </element>
       </oneOrMore>
     </element>
   </start>
   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>
   <define name="attribute-id">
     <attribute name="id">
       <data type="ID"/>
     </attribute>
   </define>
 </grammar>

or:

 start =
   element library {
     element book {
       attribute-id,
       attribute available { xsd:boolean },
       element isbn { token },
       element title {
         attribute xml:lang { xsd:language },
         token
       },
       grammar {
         start = element-author
         element-author =
           element author {
             attribute id { xsd:ID },
             parent element-name,
             parent element-born?,
             element-died?
           }
         element-died = element died { xsd:date }
       }+,
       grammar {
         start = element-character
         element-character =
           element character {
             attribute id { xsd:ID },
             parent element-name,
             parent element-born?,
             element-qualification
           }
         element-qualification = element qualification { token }
       }*
     }+
   }
 element-name = element name { token }
 element-born = element born { xsd:date }
 attribute-id = attribute id { xsd:ID }

See how "start" and named patterns have been defined in each of the three grammars composing this schema:

* "element-died" is defined in the grammar defining the "author" element and can only be used in this grammar.
* similarly, "element-qualification" is defined in the grammar defining the "character" element and can only be used there.
* "element-name", "element-born" and "attribute-id" are defined in the top level grammar. They can be used in this grammar through normal references (i.e. "ref" patterns) and can also be used in its children grammars, i.e. the grammars which are directly embedded into this one, using a "parentRef" pattern.

There is a couple of more things to note about the "parentRef" pattern:

*If the depth of imbrication of grammar is higher than two, you may run into troubles since you can only make a reference to your immediate parent grammar, not to the other grammar ancestors. The Relax NG working group has considered this issue but hasn't found any real world use case for generalizing "parentRef" patterns to higher imbrication depths. If you find one they will probably welcome a mail on the subject! In practice, if we needed to do so, we would have as a workaround to define named patterns in the intermediary grammars that would act as "proxies".
*Now that we have added the "parentRef" patterns our two schemas "author.rng" and "character.rng" cannot be used as standalone schemas to validate documents which root elements are "author" or "character" elements: they need to be embedded into grammars providing the definitions for the named patterns they are using to be complete and operational. 

!!!Merging grammars

In the preceding sections we have seen how we could use an external grammar as a single pattern. This is useful in cases like those we've seen where we want to include a content model described by an external schema at a single point, not unlike when you mount a UNIX file system: the description contained in the external grammar is "mounted" at the point where you make your reference. 

The main drawback is that you cannot individually reuse the definitions contained in the external schema. To do so, we need to introduce a new pattern, with a different semantic which will merge two grammars into a single one.

!!Merging without redefinition

In the simplest case, we will want to reuse patterns defined in common libraries of patterns without modifying them. Let's say we have defined a grammar with some common patterns which can be reused in many different schemas, such as:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
 
   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   
   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>
   
   <define name="attribute-id">
     <attribute name="id">
       <data type="ID"/>
     </attribute>
   </define>
   
   <define name="content-person">
     <ref name="attribute-id"/>
     <ref name="element-name"/>
     <optional>
       <ref name="element-born"/>
     </optional>
   </define>
   
 </grammar>
(common.rng)

Or:

 element-name = element name { token }
 element-born = element born { xsd:date }
 attribute-id = attribute id { xsd:ID }
 content-person = attribute-id, element-name, element-born?
(common.rnc)

These schemas are obviously not meant to be used as standalone schemas: they have no "start" patterns and would be considered incorrect. However, they contain definitions which can be used to write the schema of our library. To use these definitions, we need to use "include" patterns:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
 
   <include href="common.rng"/>

   <start>
     <element name="library">
       <oneOrMore>
         <element name="book">
           <ref name="attribute-id"/>
           <attribute name="available">
             <data type="boolean"/>
           </attribute>
           <element name="isbn">
             <data type="token" datatypeLibrary=""/>
           </element>
           <element name="title">
             <attribute name="xml:lang">
               <data type="language"/>
             </attribute>
             <data type="token" datatypeLibrary=""/>
           </element>
           <oneOrMore>
             <element name="author">
               <ref name="content-person"/>
               <optional>
                 <ref name="element-died"/>
               </optional>
             </element>
           </oneOrMore>
           <zeroOrMore>
             <element name="character">
               <ref name="content-person"/>
               <ref name="element-qualification"/>
             </element>
           </zeroOrMore>
         </element>
       </oneOrMore>
     </element>
   </start>

   <define name="element-died">
     <element name="died">
       <data type="date"/>
     </element>
   </define>
   
   <define name="element-qualification">
     <element name="qualification">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   
 </grammar>

The "include" pattern is translated as and "include" keyword in the compact syntax:

 include "common.rnc"
 start =
   element library {
     element book {
       attribute-id,
       attribute available { xsd:boolean },
       element isbn { token },
       element title {
         attribute xml:lang { xsd:language },
         token
       },
       element author {
         content-person,
         element-died?
       }+,
       element character {
         content-person,
         element-qualification
       }*
     }+
   }
 element-died = element died { xsd:date }
 element-qualification = element qualification { token }

Note that the name of the "include" pattern is slightly misleading. The "include" pattern here doesn't include the external grammar as a pattern (we have seen that this was the job of the "externalRef" pattern) but it includes the content of the external grammar, performing a merge of both grammars. This is exactly what we needed, though, and this is the reason why we have been able to do references to the named patterns defined in the "common.rng" grammar. 

The result of this inclusion is thus equivalent to the following monolithic schema:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
 <!-- Content of the included grammar -->
   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>
   <define name="attribute-id">
     <attribute name="id">
       <data type="ID"/>
     </attribute>
   </define>
   <define name="content-person">
     <ref name="attribute-id"/>
     <ref name="element-name"/>
     <optional>
       <ref name="element-born"/>
     </optional>
   </define>
 <!-- End of the included grammar -->
   <start>
     <element name="library">
       <oneOrMore>
         <element name="book">
           <ref name="attribute-id"/>
           <attribute name="available">
             <data type="boolean"/>
           </attribute>
           <element name="isbn">
             <data type="token" datatypeLibrary=""/>
           </element>
           <element name="title">
             <attribute name="xml:lang">
               <data type="language"/>
             </attribute>
             <data type="token" datatypeLibrary=""/>
           </element>
           <oneOrMore>
             <element name="author">
               <ref name="content-person"/>
               <optional>
                 <ref name="element-died"/>
               </optional>
             </element>
           </oneOrMore>
           <zeroOrMore>
             <element name="character">
               <ref name="content-person"/>
               <ref name="element-qualification"/>
             </element>
           </zeroOrMore>
         </element>
       </oneOrMore>
     </element>
   </start>
   <define name="element-died">
     <element name="died">
       <data type="date"/>
     </element>
   </define>
   <define name="element-qualification">
     <element name="qualification">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>
 </grammar>

or:

 element-name = element name { token }
 element-born = element born { xsd:date }
 attribute-id = attribute id { xsd:ID }
 content-person = attribute-id, element-name, element-born?

 start =
   element library {
     element book {
       attribute-id,
       attribute available { xsd:boolean },
       element isbn { token },
       element title {
         attribute xml:lang { xsd:language },
         token
       },
       element author {
         content-person,
         element-died?
       }+,
       element character {
         content-person,
         element-qualification
       }*
     }+
   }
 element-died = element died { xsd:date }
 element-qualification = element qualification { token }

!!Merging and replacing definitions

In the previous example, we have been lucky and the definitions of the common patterns which we've included were exactly matching what we needed. In the real world, this isn't always the case and it is quite handy to be able to replace the definitions found in the grammar that we're including.

Let's say that we have already written this very flat version of our schema:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

   <start>
     <ref name="element-library"/>
   </start>
   
   <define name="element-library">
     <element name="library">
       <zeroOrMore>
         <ref name="element-book"/>
       </zeroOrMore>
     </element>
   </define>
   
   <define name="element-book">
     <element name="book">
       <ref name="attribute-id"/>
       <ref name="attribute-available"/>
       <ref name="element-isbn"/>
       <ref name="element-title"/>
       <oneOrMore>
         <ref name="element-author"/>
       </oneOrMore>
       <zeroOrMore>
         <ref name="element-character"/>
       </zeroOrMore>
     </element>
   </define>
   
   <define name="element-author">
     <element name="author">
       <ref name="content-person"/>
       <optional>
         <ref name="element-died"/>
       </optional>
     </element>
   </define>
   
   <define name="element-character">
     <element name="character">
       <ref name="content-person"/>
       <ref name="element-qualification"/>
     </element>
   </define>

   <define name="element-isbn">
     <element name="isbn">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>

   <define name="element-title">
     <element name="title">
       <ref name="attribute-xml-lang"/>
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>

   <define name="attribute-xml-lang">
     <attribute name="xml:lang">
       <data type="language"/>
     </attribute>
   </define>

   <define name="attribute-available">
     <attribute name="available">
       <data type="boolean"/>
     </attribute>
   </define>

   <define name="element-name">
     <element name="name">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>

   <define name="element-born">
     <element name="born">
       <data type="date"/>
     </element>
   </define>

   <define name="element-died">
     <element name="died">
       <data type="date"/>
     </element>
   </define>

   <define name="attribute-id">
     <attribute name="id">
       <data type="ID"/>
     </attribute>
   </define>

   <define name="content-person">
     <ref name="attribute-id"/>
     <ref name="element-name"/>
     <optional>
       <ref name="element-born"/>
     </optional>
   </define>

   <define name="element-qualification">
     <element name="qualification">
       <data type="token" datatypeLibrary=""/>
     </element>
   </define>

 </grammar>
(library.rng)

or:

 start = element-library
 element-library = element library { element-book* }
 element-book =
   element book {
     attribute-id,
     attribute-available,
     element-isbn,
     element-title,
     element-author+,
     element-character*
   }
 element-author = element author { content-person, element-died? }
 element-character =
   element character { content-person, element-qualification }
 element-isbn = element isbn { token }
 element-title = element title { attribute-xml-lang, token }
 attribute-xml-lang = attribute xml:lang { xsd:language }
 attribute-available = attribute available { xsd:boolean }
 element-name = element name { token }
 element-born = element born { xsd:date }
 element-died = element died { xsd:date }
 attribute-id = attribute id { xsd:ID }
 content-person = attribute-id, element-name, element-born?
 element-qualification = element qualification
(library.rnc)

If this is a good schema used in production to validate incoming documents from a variety of patterns and we wouldn't want to modify it. However, we might have a new application that doesn't work at the level of a library but only at the level of a book. This application would need to validate instance documents with "book" root elements. Of course we wouldn't want to copy and paste the definition of our existing schema into another one since that would mean maintaining do different branches.

This is a case were we would want to redefine the "start" element of our schema. To do so, we would use an "include" pattern and embed the definitions which must be substitute to the one from the included grammar in the "include" pattern itself:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
   <include href="library.rng">
     <start>
       <ref name="element-book"/>
     </start>
   </include>
 </grammar>

Or:

 include "library.rnc" {
   start = element-book
 }

Note how the new definitions are embedded in the "include" pattern: the content of the "include" pattern is where all the redefinitions must be written. This short schema is including all the definitions from "library.rng" and redefining the "start" pattern. It validates instance documents with a "book" root element and since we are performing an inclusion instead of a copy, we will inherit any modification done on "library.rng".

We have been able to redefine the "start" pattern, but each named pattern can be redefined using the same syntax. Let's say for instance that I am not happy with the definition of the "element-name" pattern and want to check that the name is shorter than 80 characters. If I don't want (or can't) modify the original schema, I can include it and redefine this pattern:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <include href="library.rng">
     <define name="element-name">
       <element name="name">
         <data type="token">
           <param name="maxLength">80</param>
         </data>
       </element>
     </define>
   </include>
 </grammar>


Or:

 include "library.rnc" {
   element-name = element name { xsd:token{maxLength = "80"} }
 }

Here again, the grammar of "library.rnc" is merged with the grammar of the new schema (which happens to be empty) but before the merge, the definitions which are embedded in the "include" pattern are substituted to the original definitions.

The new definition can be as different from the original one as I want. Without wanting to argue that it would be a good practice, I could for instance redefine "attribute-available" and replace the attribute by an element:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <include href="library.rng">
     <define name="attribute-available">
       <element name="available">
         <data type="boolean"/>
       </element>
     </define>
   </include>
 </grammar>

Or:

 include "library.rnc" {
   attribute-available = element available { xsd:boolean }
 }

That would be rather confusing (the named pattern is called "attribute-available" and it's now describing an element) but the schema is perfectly valid and describes instance documents where the "available" attribute is replaced by an "available" element. This could also be used to remove this attribute:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
   <include href="library.rng">
     <define name="attribute-available">
       <empty/>
     </define>
   </include>
 </grammar>

Or:

 include "library.rnc" {
   attribute-available = empty
 }

Note how we are using here a new pattern named "empty". This pattern will match only text nodes made of non significant white spaces) and it will have the same effect than if the named pattern had been removed from the schema.

I have said that "include" patterns have the effect to merge the content of their grammar, after replacement of the patterns to redefine, with the content of the current grammar. This means that these redefinition can make references to any definition from either the including or the included grammars. If we want to add zero or more email addresses to out "author" element while keeping a flat structure, we could write:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" 
          datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
 
   <include href="library.rng">
   
     <define name="element-author">
       <element name="author">
         <ref name="content-person"/>
         <optional>
           <ref name="element-died"/>
         </optional>
         <zeroOrMore>
           <ref name="element-email"/>
         </zeroOrMore>
       </element>
     </define>
     
   </include>
   
   <define name="element-email">
     <element name="email">
       <data type="anyURI">
         <param name="pattern">mailto:.*</param>
       </data>
     </element>
   </define>
 </grammar>

Or:

 include "library.rnc" {
   element-author =
     element author { content-person, element-died?, element-email* }
 }
 element-email =
   element email {
     xsd:anyURI { pattern = "mailto:.*" }
   }

Here, in the redefinition of the "element-author" pattern, we are making three references to three named patterns: "content-person" and "element-died" are defined in "library.rng", i.e. the grammar which is included and the third one, "element-email" is defined in the top level grammar i.e. the including grammar.

!!Combining definitions

When we've replaced the definitions in our previous examples, the original definition was completely replaced by the new one and this can make the maintenance of these schemas more complicated than it should be. In the last example, if the included schema (library.rng) is updated and the definition of "element-author" changed to add a new element to include a telephone number, this addition is lost if we do not add it explicitly in the including schema. As far as the "element-author" pattern is concerned, this redefinition is no better than a copy paste and we'd benefit using a mechanism more similar to inheritance.

If we want to keep the definition from the included grammar, we can combine a new definition with the existing one instead of replacing it. Unlike redefinition, combination of "start" and named pattern do not take place in the "include" pattern and is done at the level of the including grammar. Actually, it isn't even necessary to include a grammar to combine definitions, but the main interest of combining definitions is to combine new definitions with existing ones from included grammars.

There are two options to combine definitions: by "choice" and by "interleave".

!Combining by choice

When definitions are combined by choice, the result is similar to using a "choice" pattern between the content of the definitions. 

A use case for this would be to define a schema accepting either a "library" or a "book" element from the schema used in the previous section. In the XML syntax, combining by choice is done through a "combine" attribute:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
   <include href="library.rng"/>
   <start combine="choice">
     <ref name="element-book"/>
   </start>
 </grammar>

In the compact syntax, combining by choice is done through using the "|=" operator (instead of "=") in the definition:

 include "library.rnc"
 start |= element-book

Note that in both cases, the combination is done outside of the inclusion. It's effect is to add a choice between the content of the "start" pattern which definition is now equivalent to :

   <start>
     <choice>
       <ref name="element-library"/>
       <ref name="element-book"/>
     </choice>
   </start>

Or:

 start = element-library | element-book

The logic behind this combination is to allow the content model corresponding to the original pattern and in addition to allow a different content. This is different for the logic behind pattern redefinitions where the original pattern was replaced by a new one.

Named patterns can be combined too and if we wanted to accept either an "available" attribute or element, we could write:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   
   <include href="library.rng"/>
   
   <define name="attribute-available" combine="choice">
     <element name="available">
       <data type="boolean"/>
     </element>
   </define>
   
 </grammar>

Or:

 include "library.rnc"
 attribute-available |= element available { xsd:boolean }

Another interesting and common case is if we want to make this attribute optional and this can be achieved by combining this pattern by choice with an "empty" pattern:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
 
   <include href="library.rng"/>
   
   <define name="attribute-available" combine="choice">
     <empty/>
   </define>
   
 </grammar>

Or:

 include "library.rnc"
 attribute-available |= empty

!Combining by interleave

We have seen how the "old" pattern could be replaced by a new one using pattern redefinition and how we could give the choice between an "old" definition and a new one using a combination by choice. The last option is to combine by interleave and the logic here is to allow to add pieces to the original content model and to let these pieces been interleaved, i.e. added anywhere before, after and between the sub patterns of the original pattern.

Do you remember the "email" element that we had added to the content of the "author" element using a redefinition? We can also use a combination by interleave to add this email pattern to the "content-person" pattern:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0" 
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   
   <include href="library.rng"/>
   
   <define name="content-person" combine="interleave">
     <zeroOrMore>
       <ref name="element-email"/>
     </zeroOrMore>
   </define>
   
   <define name="element-email">
     <element name="email">
       <data type="anyURI">
         <param name="pattern">mailto:.*</param>
       </data>
     </element>
   </define>
   
 </grammar>

Or:

 include "library.rnc"
 content-person &= element-email *
 element-email =
   element email {
     xsd:anyURI { pattern = "mailto:.*" }
   }

The effect of this combination is that the "content-model" pattern is now equivalent to an "interleave" pattern embedding both the original and the new definition, i.e.:

    <define name="content-person">
      <interleave>
        <group>
          <ref name="attribute-id"/>
          <ref name="element-name"/>
          <optional>
            <ref name="element-born"/>
          </optional>
        </group>
        <zeroOrMore>
          <ref name="element-email"/>
        </zeroOrMore>
      </interleave>
    </define>

Or:

  content-person =
    (attribute-id, element-name, element-born?) & element-email *

The effect of this definition is thus to allow any number of "email" elements before the "name" element, between the "name" element and the "born" element and after the "born element".

The logic here is to allow extension by adding new content anywhere in the original definition. This is neat and safe if the applications which read the documents are coded to ignore what they don't know. In our example, if I have designed an application to read the original content model, this application will be just fine with the new content model if it ignores the "email" elements which have been added.

We have seen how a combination by choice can be used to turn a pattern into being optional. Combination by interleave cannot reverse the process, but it can turn a pattern into being forbidden! If we don't want to end up with a schema which won't validate any instance document, we must take care to do so on a pattern which reference is made optional, such as the "element-died" pattern:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
   <include href="library.rng"/>
   <define name="element-died" combine="interleave">
     <notAllowed/>
   </define>
 </grammar>

Or:

 include "library.rnc"
 element-died &= notAllowed

Here, we are interleaving a new pattern, "notAllowed" with the content of the named pattern "element-died". The effect of this operation is that this pattern will not match any content model any longer. This is OK since the reference to the "element-died" in the definition of the "author" element is optional and the effect is that a document can be valid per the resulting schema only if there is no "died" element.

What about combining "start" patterns by interleave? This may seem weird and even illegal since we have seen "start" patterns in a context where they are using to define the root element of XML documents and that a well formed XML document can only have one root element.

Another use case where combining by interleave is handy and very widely used is to add attributes to a named pattern. In this case, the fact that interleave is unordered doesn't make any difference since attributes are always unordered.  

!!Why can't we combine definitions by group?

We have seen how to combine definitions by "interleave" and "choice" and since "group" is the third compositor, we might be tempted to combine definitions by "group". Unfortunately, definitions of named patterns are declarations and since the relative order of these declarations is considered as not significant, combining definitions by group wouldn't give reliable results and has thus been forbidden. This issue doesn't happen with "choice" and "interleave" compositors since the relative order of their children elements is not significant for a schema.

!!!A real world example: XHTML 2.0

Let's leave our library for a while to look at XHTML. The modularization of XHTML 1.1, i.e. the fact to split XHTML 1.0 which was described as a monolithic DTD into a set of independent modules described as in independent DTDs that can be combined together to create as many flavor as people may want is one of the most challenging exercise for schema languages. In their Working Drafts, the W3C HTML Working Group -now in charge of XHTML- has published a set of Relax NG schemas to describe XHTML 2.0 and its many modules which illustrates the flexibility of Relax NG to perform this type of exercises.

The solution chosen by XHTML 2.0 (see http://www.w3.org/TR/xhtml2/xhtml20_relax.html#a_xhtml20_relaxng for more detail) is to define each module by its own schema and include all these modules in a top level schema (called the "RELAX NG XHTML 2.0 Driver") :

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar ns="http://www.w3.org/2002/06/xhtml2"
         xmlns="http://relaxng.org/ns/structure/1.0"
         xmlns:x="http://www.w3.org/1999/xhtml">

  <x:h1>RELAX NG schema for XHTML 2.0</x:h1>

  <x:pre>
    Copyright &#xA9;2003 W3C&#xAE; (MIT, ERCIM, Keio), All Rights Reserved.

      Editor:   Masayasu Ishikawa &lt;mimasa@w3.org&gt;
      Revision: $Id: RngBookBuildingBlocks,v 1.3 2003/09/09 07:18:55 vdv Exp $

    Permission to use, copy, modify and distribute this RELAX NG schema
    for XHTML 2.0 and its accompanying documentation for any purpose and
    without fee is hereby granted in perpetuity, provided that the above
    copyright notice and this paragraph appear in all copies. The copyright
    holders make no representation about the suitability of this RELAX NG
    schema for any purpose.

    It is provided "as is" without expressed or implied warranty.
    For details, please refer to the W3C software license at:

      <x:a href="http://www.w3.org/Consortium/Legal/copyright-software"
      >http://www.w3.org/Consortium/Legal/copyright-software</x:a>
  </x:pre>

  <div>
    <x:h2>XHTML 2.0 modules</x:h2>

    <x:h3>Attribute Collections Module</x:h3>
    <include href="xhtml-attribs-2.rng"/>

    <x:h3>Structure Module</x:h3>
    <include href="xhtml-struct-2.rng"/>

    <x:h3>Block Text Module</x:h3>
    <include href="xhtml-blktext-2.rng"/>

    <x:h3>Inline Text Module</x:h3>
    <include href="xhtml-inltext-2.rng"/>

    <x:h3>Hypertext Module</x:h3>
    <include href="xhtml-hypertext-2.rng"/>

    <x:h3>List Module</x:h3>
    <include href="xhtml-list-2.rng"/>

    <x:h3>Linking Module</x:h3>
    <include href="xhtml-link-2.rng"/>

    <x:h3>Metainformation Module</x:h3>
    <include href="xhtml-meta-2.rng"/>

    <x:h3>Object Module</x:h3>
    <include href="xhtml-object-2.rng"/>

    <x:h3>Scripting Module</x:h3>
    <include href="xhtml-script-2.rng"/>

    <x:h3>Style Attribute Module</x:h3>
    <include href="xhtml-inlstyle-2.rng"/>

    <x:h3>Style Sheet Module</x:h3>
    <include href="xhtml-style-2.rng"/>

    <x:h3>Tables Module</x:h3>
    <include href="xhtml-table-2.rng"/>

    <x:h3>Support Modules</x:h3>

    <x:h4>Datatypes Module</x:h4>
    <include href="xhtml-datatypes-2.rng"/>

    <x:h4>Events Module</x:h4>
    <include href="xhtml-events-2.rng"/>

    <x:h4>Param Module</x:h4>
    <include href="xhtml-param-2.rng"/>

    <x:h4>Caption Module</x:h4>
    <include href="xhtml-caption-2.rng"/>
  </div>


  <div>
    <x:h2>XML Events module</x:h2>
    <include href="xml-events-1.rng"/>
  </div>

  <div>
    <x:h2>Ruby module</x:h2>
    <include href="full-ruby-1.rng"/>
  </div>

  <div>
    <x:h2>XForms module</x:h2>
    <x:p>To-Do: work out integration of XForms</x:p>
    <!--include href="xforms-1.rng"/-->
  </div>

 </grammar>

Don't worry for the moment about the "ns" attribute which we'll see in "Chapter 11: Namespaces" nor about the foreign (non Relax NG) namespaces and the "div" elements which we'll see in "Chapter 13: Annotating Schemas". One of these modules, the "Structure Module" defines the basic structure of a XHTML 2.0 document. For instance, the "head" element is defined as:

   <define name="head">
      <element name="head">
        <ref name="head.attlist"/>
        <ref name="head.content"/>
      </element>
    </define>

    <define name="head.attlist">
      <ref name="Common.attrib"/>
    </define>

    <define name="head.content">
      <ref name="title"/>
    </define>

Or:

  head = element head { head.attlist, head.content }
   head.attlist = Common.attrib
   head.content = title

This shows another design decision which is, for each element, to define a named pattern with the same name than the element (here "head") and two separated named patterns to define the list of its attributes (here "head.attlist") and its content (here "head.content"). This design decision makes it easy for other modules to add new elements and attributes just by combining these named patterns by interleave. For instance, the "Metainformation Module" adds a "meta" element to the content of the "head" element by combining by interleave the "head.content" pattern with zero or more "meta" elements:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0"
         xmlns:x="http://www.w3.org/1999/xhtml">

  <x:h1>Metainformation Module</x:h1>

  <div>
    <x:h2>The meta element</x:h2>

    <define name="meta">
      <element name="meta">
        <ref name="meta.attlist"/>
        <choice>
          <ref name="Inline.model"/>
          <oneOrMore>
            <ref name="meta"/>
          </oneOrMore>
        </choice>
      </element>
    </define>

    <define name="meta.attlist">
      <ref name="Common.attrib"/>
      <optional>
        <attribute name="name">
          <ref name="NMTOKEN.datatype"/>
        </attribute>
      </optional>
    </define>
  </div>

  <define name="head.content" combine="interleave">
    <zeroOrMore>
      <ref name="meta"/>
    </zeroOrMore>
  </define>

 </grammar>

Or:

 namespace x = "http://www.w3.org/1999/xhtml"

 meta = element meta { meta.attlist, (Inline.model | meta+) }
 meta.attlist =
   Common.attrib,
   attribute name { NMTOKEN.datatype }?
 head.content &= meta*

The fact that the content models are combined by interleave guarantees the independence between modules: we can add or remove modules independently of each other and also the independence of the resulting schema over the order in which the different modules are included in the top level schema: we can switch the "Metainformation Module" and the "Scripting Module" which both add content into the "head" element without any impact on the set of valid documents.

This modularity fully relies on combinations by interleave and Relax NG would have no easy solution if we wanted to add stuff to what has already be defined in the "head" element. Of course, if we are interested only by the "Structure Module" and want to add a "foo" element after the "title" element, we can redefine "head.content":

    <include href="xhtml-struct-2.rng">
      <define name="head.content">
        <ref name="title"/>
        <element name="foo">
          <empty/>
        </element>
      </define>
    </include>

But this won't take into account all the content added by the other modules into the "head" element.

!!!Other options

What if we really needed a feature which is really missing in Relax NG to create our building blocks? What if, for instance, we needed to reuse a name class or a datatype parameter defined once and only once in multiple locations of a schema?

If this was an absolute requirement, which is not often the case, we would have to use non Relax NG tools or features and what's unique with Relax NG compared to DTDs or W3C XML Schema is that we have two possible syntaxes, leaving the option to use either XML mechanisms with the XML syntax or plain text tools with the compact syntax.

There is no limit to the tools we may want to use to produce our result, but let's set up a possible use case and some examples of implementations.

!!A possible use case

Let's just say we want to set the set of possible characters in our documents and that we want to implement this rule in our Relax NG schemas. The pattern we might have in mind to perform this restriction could be the one we've seen as an example in "Chapter 9: W3C XML Schema Regular Expressions". It's not very complex but not very simple either:

 pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"

And of course, we would like to be able to easily update it if we had to and wouldn't want to have to copy it in each data type definition and we would like to be able to use this pattern in different contexts over different data types and eventually combined to other parameters.

!!XML tools

All the flavors of XML parsed entities (internal or external and in the internal DTD or in an external DTD) may be used in this case. Using internal entities in an internal DTD, we could for instance write:

 <?xml version = '1.0' encoding = 'utf-8' ?>
 <!DOCTYPE element [[
 <!ENTITY validChars "<param name='pattern'>[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*</param>">
 ]>
 <element xmlns="http://relaxng.org/ns/structure/1.0" name="library"
  datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <oneOrMore>
   <element name="book">
    <attribute name="id">
     <data type="NMTOKEN">&validChars;</data>
    </attribute>
    <attribute name="available">
     <data type="boolean"/>
    </attribute>
    <element name="isbn">
     <data type="NMTOKEN">&validChars;</data>
    </element>
    <element name="title">
     <attribute name="xml:lang">
      <data type="language"/>
     </attribute>
     <data type="token">&validChars;</data>
    </element>
    <zeroOrMore>
     <element name="author">
      <attribute name="id">
       <data type="NMTOKEN">&validChars;</data>
      </attribute>
      <element name="name">
       <data type="token">&validChars;</data>
      </element>
      <element name="born">
       <data type="date"/>
      </element>
      <optional>
       <element name="died">
        <data type="date"/>
       </element>
      </optional>
     </element>
    </zeroOrMore>
    <zeroOrMore>
     <element name="character">
      <attribute name="id">
       <data type="NMTOKEN">&validChars;</data>
      </attribute>
      <element name="name">
       <data type="token">&validChars;</data>
      </element>
      <element name="born">
       <data type="date"/>
      </element>
      <element name="qualification">
       <data type="token">&validChars;</data>
      </element>
     </element>
    </zeroOrMore>
   </element>
  </oneOrMore>
 </element>
 
The trickery here is to define an entity for the parameter:

 <!ENTITY validChars "<param name='pattern'>[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*</param>">

And to use this entity where we need it, for instance:

       <data type="token">&validChars;</data>

What about the compact syntax? The compact syntax doesn't support entities but if I convert this schema into the compact syntax I just get:

 element library {
   element book {
     attribute id {
       xsd:NMTOKEN {
         pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
       }
     },
     attribute available { xsd:boolean },
     element isbn {
       xsd:NMTOKEN {
         pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
       }
     },
     element title {
       attribute xml:lang { xsd:language },
       xsd:token {
         pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
       }
     },
     element author {
       attribute id {
         xsd:NMTOKEN {
           pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
         }
       },
       element name {
         xsd:token {
           pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
         }
       },
       element born { xsd:date },
       element died { xsd:date }?
     }*,
     element character {
       attribute id {
         xsd:NMTOKEN {
           pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
         }
       },
       element name {
         xsd:token {
           pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
         }
       },
       element born { xsd:date },
       element qualification {
         xsd:token {
           pattern = "[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"
         }
       }
     }*
   }+
 }

This means that as long as I keep the XML version as my reference for this schema, I can easily get the compact syntax but can't go the other way round (compact to XML) without loosing my entity definition: the fact that I am using a XML mechanism has broken the round tripping between the two syntaxes.

Other XML tools (such as XInclude or even just writing the schema as a XSLT transformation) could be used with pretty much the same effect. Depending on the case, these solutions will be supported straight away by the parser which will parse the Relax NG schema (like this is the case with out internal entity) or will require a first phase during which your schema is compiled into a fully compatible Relax NG schema.

As an example, let's use XSLT. When you need to do simple stuff, XSLT has a simplified syntax where the "xsl:stylesheet" and "xsl:template" elements may be omitted (exactly like the Relax NG "grammar" and "start" elements may be omitted in a simple Relax NG schema). That means that if we just want to use XSLT for its simplest features (here only to expend the values of variables), we can write our schema as:

 <?xml version = '1.0' encoding = 'utf-8' ?>
 <element xmlns="http://relaxng.org/ns/structure/1.0" name="library"
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xsl:version="1.0">
   <xsl:variable name="validChars">
     <param name='pattern'>[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*</param>
   </xsl:variable>
   <oneOrMore>
    <element name="book">
     <attribute name="id">
      <data type="NMTOKEN"><xsl:copy-of select="$validChars"/></data>
     </attribute>
     <attribute name="available">
      <data type="boolean"/>
     </attribute>
     <element name="isbn">
      <data type="NMTOKEN"><xsl:copy-of select="$validChars"/></data>
     </element>
     <element name="title">
      <attribute name="xml:lang">
       <data type="language"/>
      </attribute>
      <data type="token"><xsl:copy-of select="$validChars"/></data>
     </element>
     <zeroOrMore>
      <element name="author">
       <attribute name="id">
        <data type="NMTOKEN"><xsl:copy-of select="$validChars"/></data>
       </attribute>
       <element name="name">
        <data type="token"><xsl:copy-of select="$validChars"/></data>
       </element>
       <element name="born">
        <data type="date"/>
       </element>
       <optional>
        <element name="died">
         <data type="date"/>
        </element>
       </optional>
      </element>
     </zeroOrMore>
     <zeroOrMore>
      <element name="character">
       <attribute name="id">
        <data type="NMTOKEN"><xsl:copy-of select="$validChars"/></data>
       </attribute>
       <element name="name">
        <data type="token"><xsl:copy-of select="$validChars"/></data>
       </element>
       <element name="born">
        <data type="date"/>
       </element>
       <element name="qualification">
        <data type="token"><xsl:copy-of select="$validChars"/></data>
       </element>
      </element>
     </zeroOrMore>
    </element>
   </oneOrMore>
  </element>

Applied to any XML document, this transformation will produce a Relax NG schema where the XSLT instruction:

 <xsl:copy-of select="$validChars"/>

will have been replaced by the content of the variable $validChars, i.e.:

 <param name='pattern'>[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*</param>

!!Text tools

Here, the situation is different and we can only use tools which, like the XSLT example just shown above, will require a first phase to produce a schema. One of the first tools which will come to mind to people familiar with C programming is the C pre processor (CPP). The syntax for defining a text replacement with CPP is "#define" and references are just done using the name of the definition. Something equivalent to our two previous examples could thus be:

 #define VALIDCHARS  pattern = '[[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*'
 element library {
   element book {
     attribute id {
       xsd:NMTOKEN {
         VALIDCHARS
       }
     },
     attribute available { xsd:boolean },
     element isbn {
       xsd:NMTOKEN {
         VALIDCHARS
       }
     },
     element title {
       attribute xml:lang { xsd:language },
       xsd:token {
         VALIDCHARS
       }
     },
     element author {
       attribute id {
         xsd:NMTOKEN {
           VALIDCHARS
         }
       },
       element name {
         xsd:token {
           VALIDCHARS
         }
       },
       element born { xsd:date },
       element died { xsd:date }?
     }*,
     element character {
       attribute id {
         xsd:NMTOKEN {
           VALIDCHARS
         }
       },
       element name {
         xsd:token {
           VALIDCHARS
         }
       },
       element born { xsd:date },
       element qualification {
         xsd:token {
           VALIDCHARS
         }
       }
     }*
   }+
 }

And, when compiled through CPP, this gives a fully valid Relax NG schema (compact syntax) where the occurrences of "VALIDCHARS" have been replaced by the parameter.


